/*
 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
 * Licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
#include <securec.h>

#include "tee_log.h"
#include "tee_crypto_api.h"
#include "tee_object_api.h"
#include "sesrv_api.h"
#include "se_service.h"
#include <stddef.h>
#include "tee_defines.h"

struct se_reader_select {
    bool is_inse;
    bool is_ese;
    bool is_sec_flash;
    bool is_msp;
    bool is_lese;
    bool is_hese;
    bool is_invalid;
};

static struct __TEE_SEServiceHandle g_se_service;
static struct __TEE_SEReaderHandle g_se_reader[SCARD_MODE_MAX] = { { .name = "sSE_spi_0" },
                                                                   { .name = "eSE_spi_0" },
                                                                   { .name = "SecureFlash" },
                                                                   { .name = "msp" },
                                                                   { .name = "normal_ese" },
                                                                   { .name = "high_ese" } };

static bool g_is_se_inited = false;
static pthread_mutex_t g_service_mutex = PTHREAD_ROBUST_MUTEX_INITIALIZER;
static pthread_mutex_t g_se_init_mutex = PTHREAD_ROBUST_MUTEX_INITIALIZER;

static int mutex_lock_service(pthread_mutex_t *mutex)
{
    int ret;

    if (mutex == NULL)
        return SE_ERROR;

    ret = pthread_mutex_trylock(mutex);
    if (ret == EOWNERDEAD) /* owner died, use consistent to recover and lock the mutex */
        return pthread_mutex_consistent(mutex);

    return ret;
}

static int reset_reader(uint32_t id)
{
    if (id >= SCARD_MODE_MAX)
        return SE_ERROR;
    g_se_reader[id].atr_len = 0;
    (void)memset_s(g_se_reader[id].atr, sizeof(g_se_reader[id].atr), 0, sizeof(g_se_reader[id].atr));

    return SE_SUCCESS;
}

static bool is_session_valid(const TEE_SESessionHandle se_session_handle)
{
    uint32_t i;
    TEE_SESessionHandle pos = NULL;

    if (se_session_handle == NULL) {
        tloge("session is NULL\n");
        return false;
    }

    for (i = 0; i < sizeof(g_se_reader) / sizeof(g_se_reader[0]); i++) {
        dlist_for_each_entry(pos, &g_se_reader[i].session_head, struct __TEE_SESessionHandle, list) {
            if (pos != se_session_handle)
                continue;
            if (se_session_handle->reader == NULL) {
                tloge("session's reader is NULL\n");
                return false;
            }
            return true;
        }
    }

    tloge("se session handle is not in list\n");
    return false;
}

static bool is_channel_valid(const TEE_SEChannelHandle se_channel_handle)
{
    TEE_SEChannelHandle pos = NULL;

    if (se_channel_handle == NULL) {
        tloge("channel is NULL\n");
        return false;
    }

    if (!is_session_valid(se_channel_handle->session) || (se_channel_handle->session->state != SESSION_STATE_OPEN)) {
        tloge("se channel handle's session is invalid\n");
        return false;
    }

    dlist_for_each_entry(pos, &se_channel_handle->session->channel_head, struct __TEE_SEChannelHandle, list) {
        if (pos == se_channel_handle)
            return true;
    }

    tloge("se channel handle is not in list\n");
    return false;
}

static TEE_SEChannelHandle malloc_channel(TEE_SESessionHandle se_session_handle, const TEE_SEAID *se_aid)
{
    TEE_SEChannelHandle channel = NULL;

    if (se_aid->bufferLen > AID_LEN_MAX)
        return NULL;
    channel = TEE_Malloc(sizeof(*channel), 0);
    if (channel == NULL)
        return NULL;

    if (se_aid->bufferLen != 0) {
        channel->se_aid.buffer = TEE_Malloc(se_aid->bufferLen, 0);
        if (channel->se_aid.buffer == NULL) {
            TEE_Free(channel);
            return NULL;
        }

        (void)memcpy_s(channel->se_aid.buffer, se_aid->bufferLen, se_aid->buffer, se_aid->bufferLen);
    }

    channel->se_aid.bufferLen = se_aid->bufferLen;
    channel->session          = se_session_handle;

    dlist_insert_tail((struct dlist_node *)&channel->list, (struct dlist_node *)&se_session_handle->channel_head);
    se_session_handle->channel_count++;

    return channel;
}

static void free_channel(TEE_SEChannelHandle channel)
{
    bool is_channel_exist = false;

    if (channel == NULL)
        return;

    is_channel_exist = ((channel->basic_channel) && (channel->session != NULL) && (channel->session->reader != NULL));
    if (is_channel_exist)
        channel->session->reader->basic_channel_locked = false;
    if (channel->session != NULL)
        channel->session->channel_count--;
    dlist_delete(&(channel->list));
    if (channel->se_aid.buffer != NULL) {
        TEE_Free(channel->se_aid.buffer);
        channel->se_aid.buffer = NULL;
    }
    if (channel->resp_buffer != NULL) {
        TEE_Free(channel->resp_buffer);
        channel->resp_buffer = NULL;
    }
    TEE_Free(channel);
}

static TEE_Result get_apdu_res(TEE_SEChannelHandle channel, const uint8_t *resp_buffer, uint32_t resp_len)
{
    uint8_t *new_buffer = NULL;

    if (channel->resp_buffer != NULL) {
        TEE_Free(channel->resp_buffer);
        channel->resp_buffer = NULL;
    }
    channel->resp_len = 0;

    if (resp_len > APDU_SELECT_RESP_LEN || resp_len < SW_GP_LEN)
        return TEE_ERROR_BAD_PARAMETERS;
    new_buffer = TEE_Malloc(resp_len, 0);
    if (new_buffer == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    (void)memcpy_s(new_buffer, resp_len, resp_buffer, resp_len);

    channel->resp_buffer = new_buffer;
    channel->resp_len    = (unsigned short)resp_len;

    return TEE_SUCCESS;
}

static TEE_Result open_basic_channel(const TEE_SEAID *se_aid, TEE_SEChannelHandle channel,
                                     uint8_t *p_rsp, uint32_t *rsp_len)
{
    TEE_Result ret;
    struct se_transmit_info_t transmit_info = { 0 };

    transmit_info.reader_id = channel->session->reader->id;
    transmit_info.data = se_aid->buffer;
    transmit_info.data_len = se_aid->bufferLen;
    transmit_info.p_rsp = p_rsp;
    transmit_info.rsp_len = *rsp_len;
    ret = tee_se_srv_open_basic_channel(&transmit_info);
    if (ret == TEE_SUCCESS)
        *rsp_len = transmit_info.rsp_len;

    return ret;
}

static TEE_Result open_logical_channel(const TEE_SEAID *se_aid, TEE_SEChannelHandle channel,
                                       uint8_t *p_rsp, uint32_t *rsp_len)
{
    TEE_Result ret;
    struct se_transmit_info_t transmit_info = { 0 };

    transmit_info.reader_id = channel->session->reader->id;
    transmit_info.data = se_aid->buffer;
    transmit_info.data_len = se_aid->bufferLen;
    transmit_info.p_rsp = p_rsp;
    transmit_info.rsp_len = *rsp_len;
    ret = tee_se_srv_open_logical_channel(&transmit_info);
    if (ret == TEE_SUCCESS) {
        *rsp_len = transmit_info.rsp_len;
        channel->logic_channel = transmit_info.channel_id;
    }

    return ret;
}

static TEE_Result service_get_readers_init(struct se_reader_select *reader,
                                           const uint32_t *se_reader_handle_list_len)
{
    int se_type;
    bool sec_flash_status = false;

    se_type = se_srv_get_ese_type();
    tlogi("se type is %d\n", se_type);

    sec_flash_status = se_srv_get_sec_flash_status();

    reader->is_inse = ((se_type == SCARD_MODE_INSE || se_type == SCARD_MODE_BOTH) &&
                       (*se_reader_handle_list_len >= SCARD_INSE_LEN));
    reader->is_ese = ((se_type == SCARD_MODE_ESE || se_type == SCARD_MODE_BOTH) &&
                      (*se_reader_handle_list_len >= SCARD_ESE_LEN));
    reader->is_sec_flash = (sec_flash_status && *se_reader_handle_list_len >= SCARD_SECFLASH_LEN);
    reader->is_msp = (se_srv_get_msp_status() && *se_reader_handle_list_len >= SCARD_MSP_LEN);
    reader->is_lese = *se_reader_handle_list_len >= SCARD_LESE_LEN;
    reader->is_hese = *se_reader_handle_list_len >= SCARD_HESE_LEN;
    reader->is_invalid = !((reader->is_inse) || (reader->is_ese) || (reader->is_sec_flash) || (reader->is_msp) ||
        (reader->is_lese) || (reader->is_hese));
    return TEE_SUCCESS;
}

static TEE_Result session_open_channel_check(TEE_SESessionHandle se_session_handle, TEE_SEAID *se_aid,
                                             TEE_SEChannelHandle *se_channel_handle)
{
    bool is_bad_param = false;

    is_bad_param = ((se_aid == NULL) || (se_channel_handle == NULL) ||
                    (se_aid->bufferLen == 0 && se_aid->buffer != NULL) ||
                    ((se_aid->bufferLen != 0) && ((se_aid->bufferLen > AID_LEN_MAX) ||
                                                  (se_aid->bufferLen < AID_LEN_MIN) || (se_aid->buffer == NULL))));
    if (is_bad_param) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if ((!is_session_valid(se_session_handle)) || (se_session_handle->state != SESSION_STATE_OPEN)) {
        tloge("session handle is invalid\n");
        return TEE_ERROR_BAD_STATE;
    }

    return TEE_SUCCESS;
}

static TEE_Result se_reader_check(TEE_SEReaderHandle se_reader_handle)
{
    if (se_reader_handle == NULL) {
        tloge("se reader handle is null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if ((se_reader_handle != &g_se_reader[SCARD_MODE_INSE]) &&
        (se_reader_handle != &g_se_reader[SCARD_MODE_ESE]) &&
        (se_reader_handle != &g_se_reader[SCARD_MODE_SECURE_FLASH]) &&
        (se_reader_handle != &g_se_reader[SCARD_MODE_MSP]) &&
        (se_reader_handle != &g_se_reader[SCARD_MODE_LESE]) &&
        (se_reader_handle != &g_se_reader[SCARD_MODE_HESE])) {
        tloge("se reader handle is invalid\n");
        return TEE_ERROR_ITEM_NOT_FOUND;
    }

    return TEE_SUCCESS;
}

static void init_tee_se_api(void)
{
    unsigned int i;

    if (mutex_lock_service(&g_se_init_mutex) != MUTEX_SUCCESS) {
        tloge("failed to get se init lock\n");
        return;
    }

    if (g_is_se_inited)
        goto UNLOCK_MUTEX;

    for (i = 0; i < SCARD_MODE_MAX; i++) {
        g_se_reader[i].id                            = i;
        g_se_reader[i].property.sePresent            = true;
        g_se_reader[i].property.teeOnly              = true;
        g_se_reader[i].property.selectResponseEnable = true;
        g_se_reader[i].basic_channel_locked          = false;
        g_se_reader[i].session_count                 = 0;
        if (reset_reader(i) != SE_SUCCESS)
            tloge("reset reader failed\n");
        dlist_init(&g_se_reader[i].session_head);
    }

    g_is_se_inited = true;

UNLOCK_MUTEX:
    if (pthread_mutex_unlock(&g_se_init_mutex))
        tloge("unlock se init mutex failed\n");
}

/*
 * -----------------------------------------------------------------------------------------------
 * APIs under the line are defined by Global Platform, need to follow Global Platform code style
 * don't change function name / return value type / parameters types / parameters names
 * -----------------------------------------------------------------------------------------------
 */
TEE_Result se_internal_service_open(TEE_SEServiceHandle *se_service_handle)
{
    init_tee_se_api();

    if ((se_service_handle == NULL) || (!g_is_se_inited)) {
        tloge("params are invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (mutex_lock_service(&g_service_mutex) != MUTEX_SUCCESS) {
        tloge("mutex_lock_service fail\n");
        return TEE_ERROR_ACCESS_CONFLICT;
    }
    *se_service_handle = &g_se_service;

    return TEE_SUCCESS;
}

void se_internal_service_close(TEE_SEServiceHandle se_service_handle)
{
    if (!g_is_se_inited)
        return;
    if (se_service_handle == &g_se_service) {
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_INSE]);
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_ESE]);
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_SECURE_FLASH]);
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_MSP]);
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_LESE]);
        TEE_SEReaderCloseSessions(&g_se_reader[SCARD_MODE_HESE]);
        (void)pthread_mutex_unlock(&g_service_mutex);
    }
}

TEE_Result se_internal_service_get_readers(TEE_SEServiceHandle se_service_handle,
    TEE_SEReaderHandle *se_reader_handle_list,
    uint32_t *se_reader_handle_list_len)
{
    struct se_reader_select reader = { 0 };
    TEE_Result ret;

    if ((se_reader_handle_list == NULL) || (se_reader_handle_list_len == NULL)) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (se_service_handle != &g_se_service) {
        tloge("se service handle is invalid\n");
        return TEE_ERROR_ITEM_NOT_FOUND;
    }

    ret = service_get_readers_init(&reader, se_reader_handle_list_len);
    if (ret != TEE_SUCCESS)
        return ret;
    if (reader.is_invalid)
        return TEE_ERROR_SHORT_BUFFER;
    if (reader.is_inse) {
        tloge("here is entry");
        se_reader_handle_list[SCARD_MODE_INSE] = &g_se_reader[SCARD_MODE_INSE];
        *se_reader_handle_list_len             = SCARD_INSE_LEN;
    }
    if (reader.is_ese) {
        tloge("ese here is entry");
        se_reader_handle_list[SCARD_MODE_ESE]  = &g_se_reader[SCARD_MODE_ESE];
        *se_reader_handle_list_len             = SCARD_ESE_LEN;
    }
    if (reader.is_sec_flash) {
        tloge("secflash here is entry");
        se_reader_handle_list[SCARD_MODE_SECURE_FLASH] = &g_se_reader[SCARD_MODE_SECURE_FLASH];
        *se_reader_handle_list_len                     = SCARD_SECFLASH_LEN;
    }
    if (reader.is_msp) {
        tloge("msp here is entry");
        se_reader_handle_list[SCARD_MODE_MSP] = &g_se_reader[SCARD_MODE_MSP];
        *se_reader_handle_list_len            = SCARD_MSP_LEN;
    }
    if (reader.is_lese) {
        tloge("lese here is entry");
        se_reader_handle_list[SCARD_MODE_LESE] = &g_se_reader[SCARD_MODE_LESE];
        *se_reader_handle_list_len            = SCARD_LESE_LEN;
    }
    if (reader.is_hese) {
        tloge("hese here is entry");
        se_reader_handle_list[SCARD_MODE_HESE] = &g_se_reader[SCARD_MODE_HESE];
        *se_reader_handle_list_len            = SCARD_HESE_LEN;
    }

    return TEE_SUCCESS;
}

void se_internal_reader_get_properties(TEE_SEReaderHandle se_reader_handle,
    TEE_SEReaderProperties *reader_properties)
{
    if ((se_reader_check(se_reader_handle) != TEE_SUCCESS) || (reader_properties == NULL)) {
        tloge("params are invalid\n");
        return;
    }
    *reader_properties = se_reader_handle->property;
}

TEE_Result se_internal_reader_get_name(TEE_SEReaderHandle se_reader_handle,
    char *reader_name, uint32_t *reader_name_len)
{
    bool is_bad_param = false;
    TEE_Result ret;

    ret = se_reader_check(se_reader_handle);
    if (ret != TEE_SUCCESS)
        return ret;

    is_bad_param = ((reader_name == NULL) || (reader_name_len == NULL));
    if (is_bad_param) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (se_reader_handle->name == NULL) {
        tloge("se reader handle name is null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (strnlen(se_reader_handle->name, READER_NAME_LEN + 1) > READER_NAME_LEN) {
        tloge("se reader name is invalid\n");
        return TEE_ERROR_BAD_FORMAT;
    }
    if (*reader_name_len < (strlen(se_reader_handle->name) + 1)) {
        tloge("reader name len is invalid\n");
        return TEE_ERROR_SHORT_BUFFER;
    }

    (void)memset_s(reader_name, *reader_name_len, 0, *reader_name_len);
    if (strncpy_s(reader_name, *reader_name_len, se_reader_handle->name, strlen(se_reader_handle->name)) != EOK)
        return TEE_ERROR_SECURITY;
    *reader_name_len = strlen(se_reader_handle->name) + 1;

    return TEE_SUCCESS;
}

TEE_Result se_internal_reader_open_session(TEE_SEReaderHandle se_reader_handle,
    TEE_SESessionHandle *se_session_handle)
{
    TEE_Result ret;
    struct __TEE_SESessionHandle *session = NULL;

    ret = se_reader_check(se_reader_handle);
    if (ret != TEE_SUCCESS)
        return ret;

    if (se_session_handle == NULL) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    session = TEE_Malloc(sizeof(*session), 0);
    if (session == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    if (se_reader_handle->id >= SCARD_MODE_MAX) {
        tloge("se reader id is invalid\n");
        TEE_Free(session);
        return TEE_ERROR_BAD_PARAMETERS;
    }
    if (se_reader_handle->session_count == 0) {
        /*
         * init SE with communication
         * atr & atrlen not implement in SE driver
         */
        uint32_t len_int = ATR_LEN_MAX;

        ret = se_srv_connect(se_reader_handle->id, se_reader_handle->atr, &len_int);
        if (ret != TEE_SUCCESS) {
            tloge("se srv connect failed\n");
            TEE_Free(session);
            return ret;
        }
        se_reader_handle->atr_len = (unsigned short)len_int;
    }

    se_reader_handle->session_count++;

    session->reader = se_reader_handle;
    dlist_init(&session->channel_head);
    session->state = SESSION_STATE_OPEN;
    dlist_insert_tail((struct dlist_node *)&session->list, (struct dlist_node *)&se_reader_handle->session_head);

    *se_session_handle = session;

    return TEE_SUCCESS;
}

void se_internal_reader_close_sessions(TEE_SEReaderHandle se_reader_handle)
{
    TEE_SESessionHandle pos  = NULL;
    TEE_SESessionHandle n    = NULL;

    if (se_reader_check(se_reader_handle) != TEE_SUCCESS)
        return;

    dlist_for_each_entry_safe(pos, n, &se_reader_handle->session_head, struct __TEE_SESessionHandle, list)
        TEE_SESessionClose(pos);
}

/* atr & atr_len not implement in SE driver */
TEE_Result se_internal_session_get_atr(TEE_SESessionHandle se_session_handle,
    void *atr, uint32_t *atr_len)
{
    if (!is_session_valid(se_session_handle) || (se_session_handle->state != SESSION_STATE_OPEN)) {
        tloge("session is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (atr == NULL || atr_len == NULL) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (se_session_handle->reader->atr_len > ATR_LEN_MAX) {
        tloge("session handle's atr len is too long\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (*atr_len < se_session_handle->reader->atr_len) {
        tloge("atr len is too short\n");
        return TEE_ERROR_SHORT_BUFFER;
    }

    if (memcpy_s(atr, *atr_len, se_session_handle->reader->atr, se_session_handle->reader->atr_len) != EOK) {
        tloge("cpy atr failed\n");
        return TEE_ERROR_SECURITY;
    }
    *atr_len = (uint32_t)se_session_handle->reader->atr_len;

    return TEE_SUCCESS;
}

TEE_Result se_internal_session_is_closed(TEE_SESessionHandle se_session_handle)
{
    if (!is_session_valid(se_session_handle))
        return TEE_SUCCESS;

    /* check with communication */
    if (se_session_handle->state == SESSION_STATE_INVALID)
        return TEE_ERROR_COMMUNICATION;
    else if (se_session_handle->state == SESSION_STATE_OPEN)
        return TEE_ERROR_BAD_STATE;
    else
        return TEE_SUCCESS;
}

void se_internal_session_close(TEE_SESessionHandle se_session_handle)
{
    if (!is_session_valid(se_session_handle) || (se_session_handle->state != SESSION_STATE_OPEN)) {
        tloge("failed to close a invalid session\n");
        return;
    }

    TEE_SESessionCloseChannels(se_session_handle);
    if (se_session_handle->reader->id >= SCARD_MODE_MAX)
        return;

    if (se_session_handle->reader->session_count > 0)
        se_session_handle->reader->session_count--;
    dlist_delete((struct dlist_node *)&se_session_handle->list);

    if (se_session_handle->reader->session_count == 0) {
        /* de-init SE with communication */
        TEE_Result ret;
        ret = se_srv_disconnect(se_session_handle->reader->id);
        if (ret != TEE_SUCCESS)
            tloge("scard disconnect failed, ret=0x%x\n", ret);
        if (reset_reader(se_session_handle->reader->id) != SE_SUCCESS)
            tloge("reset reader %u failed\n", se_session_handle->reader->id);
    }
    se_session_handle->reader = NULL;
    TEE_Free(se_session_handle);
}

void se_internal_session_close_channels(TEE_SESessionHandle se_session_handle)
{
    TEE_SEChannelHandle pos = NULL;
    TEE_SEChannelHandle n   = NULL;

    if (!is_session_valid(se_session_handle) || (se_session_handle->state != SESSION_STATE_OPEN)) {
        tloge("failed to close a invalid session\n");
        return;
    }

    dlist_for_each_entry_safe(pos, n, &se_session_handle->channel_head, struct __TEE_SEChannelHandle, list)
        TEE_SEChannelClose(pos);
}

TEE_Result se_internal_session_open_basic_channel(TEE_SESessionHandle se_session_handle,
    TEE_SEAID *se_aid, TEE_SEChannelHandle *se_channel_handle)
{
    TEE_Result ret;
    TEE_SEChannelHandle channel = NULL;
    uint8_t p_rsp[APDU_SELECT_RESP_LEN] = { 0 };
    uint32_t rsp_len = APDU_SELECT_RESP_LEN;

    ret = session_open_channel_check(se_session_handle, se_aid, se_channel_handle);
    if (ret != TEE_SUCCESS) {
        tloge("session open channel check failed\n");
        return ret;
    }

    if (se_session_handle->reader->basic_channel_locked) {
        tloge("basic channel is locked\n");
        return TEE_ERROR_NOT_SUPPORTED;
    }

    channel = malloc_channel(se_session_handle, se_aid);
    if (channel == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;
    channel->basic_channel = true;
    channel->logic_channel = 0;

    ret = open_basic_channel(se_aid, channel, p_rsp, &rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("open basic channel failed\n");
        free_channel(channel);
        return ret;
    }
    ret = get_apdu_res(channel, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("get apdu res ret=0x%x\n", ret);
        TEE_SEChannelClose(channel);
        return ret;
    }

    se_session_handle->reader->basic_channel_locked = true;
    *se_channel_handle = channel;

    return TEE_SUCCESS;
}

TEE_Result se_internal_session_open_logical_channel(TEE_SESessionHandle se_session_handle,
    TEE_SEAID *se_aid, TEE_SEChannelHandle *se_channel_handle)
{
    TEE_Result ret;
    TEE_SEChannelHandle channel = NULL;
    uint8_t p_rsp[APDU_SELECT_RESP_LEN] = { 0 };
    uint32_t rsp_len = APDU_SELECT_RESP_LEN;

    ret = session_open_channel_check(se_session_handle, se_aid, se_channel_handle);
    if (ret != TEE_SUCCESS) {
        tloge("session open channel check failed\n");
        return ret;
    }

    channel = malloc_channel(se_session_handle, se_aid);
    if (channel == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    ret = open_logical_channel(se_aid, channel, p_rsp, &rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("open logical channel failed\n");
        free_channel(channel);
        return ret;
    }
    ret = get_apdu_res(channel, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("get apdu res ret=0x%x\n", ret);
        TEE_SEChannelClose(channel);
        return ret;
    }

    *se_channel_handle = channel;

    return TEE_SUCCESS;
}

void se_internal_channel_close(TEE_SEChannelHandle se_channel_handle)
{
    struct se_transmit_info_t transmit_info = { 0 };

    if (!is_channel_valid(se_channel_handle))
        return;

    transmit_info.reader_id = se_channel_handle->session->reader->id;
    transmit_info.channel_id = se_channel_handle->logic_channel;
    tee_se_srv_close_channel(&transmit_info);

    free_channel(se_channel_handle);
}

TEE_Result se_internal_channel_select_next(TEE_SEChannelHandle se_channel_handle)
{
    uint8_t p_rsp[APDU_SELECT_RESP_LEN] = { 0 };
    uint32_t rsp_len = APDU_SELECT_RESP_LEN;
    bool is_bad_param = false;
    TEE_Result ret;
    struct se_transmit_info_t transmit_info = { 0 };

    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }
    is_bad_param =
        ((se_channel_handle->se_aid.bufferLen == 0 && se_channel_handle->se_aid.buffer != NULL) ||
         ((se_channel_handle->se_aid.bufferLen != 0) &&
          ((se_channel_handle->se_aid.bufferLen > AID_LEN_MAX) || (se_channel_handle->se_aid.bufferLen < AID_LEN_MIN) ||
           (se_channel_handle->se_aid.buffer == NULL))));
    if (is_bad_param) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    transmit_info.reader_id = se_channel_handle->session->reader->id;
    transmit_info.channel_id = se_channel_handle->logic_channel;
    transmit_info.data = se_channel_handle->se_aid.buffer;
    transmit_info.data_len = se_channel_handle->se_aid.bufferLen;
    transmit_info.p_rsp = p_rsp;
    transmit_info.rsp_len = rsp_len;
    ret = tee_se_srv_select_channel(&transmit_info);
    rsp_len = transmit_info.rsp_len;
    if (ret != TEE_SUCCESS) {
        tloge("select channel failed\n");
        return ret;
    }
    ret = get_apdu_res(se_channel_handle, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS)
        tloge("get apdu res ret=0x%x\n", ret);
    return ret;
}

TEE_Result se_internal_channel_get_select_response(TEE_SEChannelHandle se_channel_handle,
    void *response, uint32_t *response_len)
{
    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (response == NULL || response_len == NULL) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if ((*response_len < se_channel_handle->resp_len) || (se_channel_handle->resp_buffer == NULL)) {
        tloge("params are invalid\n");
        return TEE_ERROR_SHORT_BUFFER;
    }

    if (memcpy_s(response, *response_len, se_channel_handle->resp_buffer, se_channel_handle->resp_len) != EOK) {
        tloge("cpy response failed\n");
        return TEE_ERROR_SECURITY;
    }
    *response_len = (uint32_t)se_channel_handle->resp_len;

    return TEE_SUCCESS;
}

TEE_Result se_internal_channel_transmit(TEE_SEChannelHandle se_channel_handle,
    void *command, uint32_t command_len,
    void *response, uint32_t *response_len)
{
    TEE_Result ret;
    bool is_bad_param = false;
    struct se_transmit_info_t transmit_info = { 0 };

    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    is_bad_param = ((command == NULL) || (command_len == 0) ||
        (response == NULL) || (response_len == NULL) || (*response_len == 0));
    if (is_bad_param) {
        tloge("params are null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (command_len < APDU_LEN_MIN) {
        tloge("command len is too short\n");
        return TEE_ERROR_COMMUNICATION;
    }

    transmit_info.reader_id = se_channel_handle->session->reader->id;
    transmit_info.channel_id = se_channel_handle->logic_channel;
    transmit_info.data = command;
    transmit_info.data_len = command_len;
    transmit_info.p_rsp = response;
    transmit_info.rsp_len = *response_len;
    if (se_channel_handle->is_secure)
        ret = tee_scp_transmit(&transmit_info);
    else
        ret = tee_se_srv_transmit(&transmit_info);
    if (ret != TEE_SUCCESS) {
        tloge("SE channel transmit ret=0x%x\n", ret);
        return ret;
    }
    *response_len = transmit_info.rsp_len;

    return TEE_SUCCESS;
}

TEE_Result se_internal_secure_channel_open(TEE_SEChannelHandle se_channel_handle,
    TEE_SC_Params *sc_params)
{
    TEE_Result ret;

    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (sc_params == NULL) {
        tloge("sc params is null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if ((sc_params->scSecurityLevel != TEE_SC_CR_ENC_MAC) || (sc_params->scType != TEE_SC_TYPE_SCP03)) {
        tloge("se security level is not support\n");
        return TEE_ERROR_NOT_SUPPORTED;
    }

    tee_secure_clean_scp();
    ret = tee_secure_authenticate_channel(se_channel_handle, sc_params);
    if (ret != TEE_SUCCESS) {
        tloge("secure authenticate channel fail, ret = 0x%x\n", ret);
        tee_secure_clean_scp();
    }
    return ret;
}

void se_internal_secure_channel_close(TEE_SEChannelHandle se_channel_handle)
{
    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return;
    }

    se_channel_handle->is_secure = false;
    tee_secure_clean_scp();
}

TEE_Result se_internal_channel_get_id(TEE_SEChannelHandle se_channel_handle,
    uint8_t *channel_id)
{
    if (!is_channel_valid(se_channel_handle)) {
        tloge("channel is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (channel_id == NULL) {
        tloge("channel id is null\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    *channel_id = se_channel_handle->logic_channel;

    return TEE_SUCCESS;
}
